
/* It will be easier to implement a parser which generates assembly
 * rather than bytecode, so I'm gonna go ahead and implement a
 * macro assembler.  This will also make it a lot easier to get
 * existing compilers to target the VM.  */


//#include "asm.h"

#include <kernel/kernel.h>
#include <kernel/handle/handle.h>
#include <kernel/block/block.h>
#include <kernel/userid/userid.h>
#include <kernel/vm/header.h>
#include <kernel/vm/state.h>
#include <library/string/string.h>

#include <stdio.h>

userid ID;
handle In;
handle Out;
handle Error;

#define TOKENLEN 16
char Token [TOKENLEN + 1] = "oops!";
char *String = NULL;
char Flag = 0;
char **LabelList = NULL;
size LabelListSize = 0;
vm_Datum *LabelValue = NULL;

vm_Header Header;


static int sink (handle _h, const char *_name)
{

}


extern int system_asm_init ()
{
	ID = userid_request ();

	In = handle_request ("system.asm.in", ID);
	Out = handle_request ("system.asm.out", ID);
	Error = handle_request ("kernel.error", ID);
}


extern int system_asm_cleanup ()
{
	userid_release (ID);

	handle_release (In);
	handle_release (Out);
	handle_release (Error);

	block_release (String);
}


static int lookupconstant (const char *_label)
{
	int i;

	for (i = 0; i < LabelListSize; ++i)
	{
		if (stringequal (LabelList [i], _label))
		{
			return -1;
		}
	}

	return i;
}


static int defineconstant (const char *_label)
{
	if (lookupconstant (_label) == -1)
	{
		return -1;
	}

	++LabelListSize;
	LabelList = block_resize (LabelList, LabelListSize * sizeof (char *));
	LabelValue = block_resize (LabelValue, LabelListSize * sizeof (char *));
	LabelList [LabelListSize - 1] = block_request (stringsize (_label));
	stringcopy (LabelList [LabelListSize - 1], _label, TOKENLEN);

	return 0;
}



static int defineint (const char *_label, int _i)
{
	if (defineconstant (_label) != 0)
	{
		return -1;
	}

	LabelValue [LabelListSize - 1].Integer = _i;
}


static int definefloat (const char *_label, int _f)
{
	if (defineconstant (_label) != 0)
	{
		return -1;
	}

	LabelValue [LabelListSize - 1].Float = _f;
}


static char notdelim ()
{
	char c;

	if (handle_read (In, &c, sizeof (char)) == -1)
	{
		return 0;
	}

	switch (c)
	{
	case ' ' :
	case '\n' :
	case '\t' :
		return 0;
	}

	return c;
}

static const char *string ()
{
	size sz = 0, toksz;
	char *p;

	while (1)
	{
		toksz = handle_peak (In, Token, TOKENLEN);
		Token [toksz] = '\0';

		if ((p = stringfirst (Token, "\"")) == NULL)
		{
			sz += TOKENLEN;

			String = block_resize (String, sz);
			
			handle_read (In, String, TOKENLEN);
		}
		else
		{
			sz += Token - p + 1;

			String = block_resize (String, sz);

			handle_read (In, String, Token - p);

			String [Token - p] = '\0';

			return String;
		}
	}

}


static const char *next ()
{
	char c;
	int i;

	handle_peak (In, &c, sizeof (char));

	if (c == '\"')
	{
		Flag = 1;
		return string ();
	}

	Flag = 0;

	for (i = 0; i < TOKENLEN - 1; ++i)
	{
		c = notdelim ();

		if (c)
		{
			Token [i] = c;
		}
		else
		{
			break;
		}
	}

	Token [i] = '\0';

	return Token;
}


static const char *token ()
{
	if (Flag == 0)
	{
		return Token;
	}
	else
	{
		return String;
	}
}


static void match (const char *_token)
{

	if (!stringequal (_token, token ()))
	{
		handle_writestring (Error, "asm: expected '");
		handle_writestring (Error, _token);
		handle_writestring (Error, "', found '");
		handle_writestring (Error, token ());
		handle_writestring (Error, "'\n");
	}

	next ();
}


static void agentname ()
{
	match ("agent");

	stringcopy (Header.AgentName, token (), VM_NAMELEN);
	next ();
}


static void end ()
{
	match ("end");
}


static void statement ()
{
}


static void agent ()
{
	agentname ();

//	while (!stringequal (token (), "end"))
	{
//		statement ();
//		next ();
	}

	end ();
}


int main ()
{
	kernel_init ();
	user_device_unix_init ();
	system_asm_init ();
	char buf [10];

	handle_read (130, buf, 10);

	handle_writestring (In, "blah agent test end");

	next ();
	agent ();

	system_asm_cleanup ();
}
